#ifndef PUNTERO_CPP
#define PUNTERO_CPP

#include <Assert.h>
#include <typeinfo.h>
#include "Puntero.h"

template<class T>
Puntero<T>::Puntero(T* ptr)
: MemoryShare()
{
	m_Ptr = ptr;
	if (m_Ptr != NULL)
		ReservarMemoria(new PunteroColector(m_Ptr), typeid(T).name());
}

template<class T>
Puntero<T>::Puntero(const Puntero<T> &p)
: MemoryShare(p)
{
	m_Ptr = p.m_Ptr;
}

template<class T>
Puntero<T>::Puntero(T* ptr, const MemoryShare& m)
: MemoryShare(m)
{
	m_Ptr = ptr;
}

template<class T>
Puntero<T>::~Puntero()
{
}

template<class T>
T* Puntero<T>::operator->() const
{
	assert(m_Ptr != NULL);
	return m_Ptr;
}

template <class T>
Puntero<T>& Puntero<T>::operator=(const Puntero<T>& p)
{
	if (&p != this && p.m_Ptr != m_Ptr)
	{
		m_Ptr = p.m_Ptr;
		MemoryShare::operator=((MemoryShare&)p);
	}
	return *this;
}

template <class T>
bool Puntero<T>::operator==(const Puntero<T>& p) const
{
	if (m_Ptr == p.m_Ptr) return true;

	return m_Ptr != NULL && p.m_Ptr != NULL && *(m_Ptr) == *(p.m_Ptr);
}

template <class T>
bool Puntero<T>::operator!=(const Puntero<T>& p) const
{
	return !(*this == p);
}

template <class T>
bool Puntero<T>::operator<(const Puntero<T>& p) const
{
	if (m_Ptr == NULL) 
		return p.m_Ptr != NULL;
	else
		return p.m_Ptr != NULL && *(m_Ptr) < *(p.m_Ptr);
}

template <class T>
bool Puntero<T>::operator>(const Puntero<T>& p) const
{
	if (m_Ptr == NULL) 
		return false;
	else
		return p.m_Ptr == NULL || *(m_Ptr) > *(p.m_Ptr);
}

template <class T>
bool Puntero<T>::operator<=(const Puntero<T>& p) const
{
	return (*this == p) || (*this < p);
}

template <class T>
bool Puntero<T>::operator>=(const Puntero<T>& p) const
{
	return (*this == p) || (*this > p);
}

template <class T>
template <class U>
Puntero<U> Puntero<T>::Cast() const
{
	return Puntero<U>((U*)m_Ptr, (MemoryShare&)*this);
}

template <class T>
ostream& operator<< <>(ostream& out, const Puntero<T>& p)
{
	if (p.m_Ptr != NULL)
		out << *(p.m_Ptr);
	else
		out << "NULL";
	return out;
}

template <class T>
Puntero<T>::PunteroColector::PunteroColector(T* ptr)
{
	m_Ptr = ptr;
}

template <class T>
void Puntero<T>::PunteroColector::LiberarMemoria()
{
	delete m_Ptr;
}

#endif